#pragma once

#include <vulkan/vulkan_raii.hpp>
#include "Scene/Mesh.hpp"
namespace Lumine
{
    class LumineBuffer
    {
    protected:
        vk::raii::Buffer buffer = nullptr;
        vk::raii::DeviceMemory bufferMemory = nullptr;
        vk::DeviceSize size;
    public:
        LumineBuffer() = default;
        LumineBuffer(const LumineBuffer &) = delete;
        LumineBuffer &operator=(const LumineBuffer &) = delete;
        // 允许移动操作：让编译器生成默认的移动构造函数和移动赋值运算符
        // 这对于 RAII 对象是必须的，因为它转移了底层 Vulkan 句柄的所有权
        LumineBuffer(LumineBuffer &&) = default;
        LumineBuffer &operator=(LumineBuffer &&) = default;

        virtual void Create(vk::DeviceSize size) {}

        void *MapMemory(vk::DeviceSize size) { return bufferMemory.mapMemory(0, size); }

        void UnMapMemory() { bufferMemory.unmapMemory(); }

        virtual void Bind(const vk::raii::CommandBuffer &cmd) = 0;

        void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::raii::Buffer &buffer, vk::raii::DeviceMemory &bufferMemory);

        virtual void cleanUp() {};
        const vk::raii::Buffer &Buffer() const { return buffer; }
        const vk::raii::DeviceMemory &Memory() const { return bufferMemory; }

    public:
        /// @brief 从物理设备的内存属性中搜索对应的内存类型
        /// @param pd PhysicalDevice 物理设备
        /// @param typeFilter
        /// @param props
        /// @return
        static uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags props);

        void copyBuffer(const vk::raii::Buffer &src, const vk::raii::Buffer &dst, vk::DeviceSize size);

        /// @brief
        /// @param outImageView
        /// @param image
        /// @param format
        static void createTextureImageView(vk::raii::ImageView &outImageView,vk::ImageAspectFlags aspect, const vk::raii::Image &image, vk::Format format);

        /// @brief 对图像进行布局转换
        /// @param image 
        /// @param format 
        /// @param oldLayout 
        /// @param newLayout 
        static void transitionImageLayout(const vk::raii::Image &image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
    
    
        static void createTextureSampler(vk::raii::Sampler &sampler);
    };
}